package com.taoxeo.apollo.login;

import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class RestLoginMoudle implements LoginModule {
	private final Logger log = LoggerFactory.getLogger(RestLoginMoudle.class);
	private Subject subject;
	private CallbackHandler callbackHandler;
	private Principal principal;
	private final String USER_FIELD = "user_field";
	private final String USERNAME_FIELD = "username_field";
	private final String PASSWORD_FIELD = "password_field";

	private String auth_url;
	private String user_field = "uid";
	private String username_field = "username";
	private String password_field = "password";

	@Override
	public void initialize(Subject subject, CallbackHandler callbackHandler,
			Map<String, ?> sharedState, Map<String, ?> options) {
		this.subject = subject;
		this.callbackHandler = callbackHandler;

		auth_url = (String) options.get("auth_url");
		if (options.containsKey(USER_FIELD))
			user_field = (String) options.get(USER_FIELD);
		if (options.containsKey(USERNAME_FIELD))
			username_field = (String) options.get(USERNAME_FIELD);
		if (options.containsKey(PASSWORD_FIELD))
			password_field = (String) options.get(PASSWORD_FIELD);
	}

	@Override
	public boolean login() throws LoginException {
		log.debug("Login by:{}", auth_url);

		NameCallback nameCallback = new NameCallback(username_field);
		PasswordCallback passwordCallback = new PasswordCallback(
				password_field, false);
		principal = null;

		try {
			if (callbackHandler != null)
				callbackHandler.handle(new Callback[] { nameCallback,
						passwordCallback });

		} catch (IOException e) {
			log.debug("Unable to process callback: " + e, e);
			throw new LoginException(e.toString());
		} catch (UnsupportedCallbackException e) {
			log.debug("Unsupported callback:" + e, e);
			throw new LoginException(e.toString());
		}

		// TODO LOGIN
		try {
			String id = restLogin(nameCallback.getName(), new String(passwordCallback.getPassword()));
			principal = new com.sun.security.auth.UserPrincipal(id);
			return true;
		} catch (AuthenticationException e) {
			log.debug("login error");
		}
		
		return false;
	}

	@Override
	public boolean commit() throws LoginException {
		subject.getPrincipals().add(principal);
		log.debug("commit principal {}",principal);
		return true;
	}

	@Override
	public boolean abort() throws LoginException {
		subject.getPrincipals().remove(principal);
		return true;
	}

	@Override
	public boolean logout() throws LoginException {
		subject.getPrincipals().remove(principal);
		return true;
	}

	private String restLogin(String username, String password) throws AuthenticationException {
		HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
		CloseableHttpClient httpClient = httpClientBuilder.build();
//		"http://ws.taoxeo.com/j_spring_security_check"
		HttpPost httppost = new HttpPost(auth_url);
		List<NameValuePair> params = new ArrayList<NameValuePair>();  
        params.add(new BasicNameValuePair(username_field, username));  
        params.add(new BasicNameValuePair(password_field, password));
		try {
			httppost.setEntity(new UrlEncodedFormEntity(params,"UTF-8"));
			String user = httpClient.execute(httppost, new ResponseHandler<String>() {
				@Override
				public String handleResponse(HttpResponse response)
						throws ClientProtocolException, IOException {
					int httpstatus = response.getStatusLine().getStatusCode();
					if(httpstatus == 200){
						String jsonstring = EntityUtils.toString(response.getEntity());
						JSONObject json = JSON.parseObject(jsonstring);
						String[] keys = user_field.split("\\.");
						
						for(int i = 0 ; i < keys.length; i++){
							if(i == keys.length -1){
								return json.getString(keys[i]);
							}
							else{
								json = json.getJSONObject(keys[i]);
							}
						}
					}
					return null;
				}
			});
			if(user == null){
				throw new AuthenticationException();
			}
			return user;
		} catch (Exception e) {
			throw new AuthenticationException();
		} finally{
			try {
				httpClient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
